#include <iostream>
#include <vector>
#include "checker.h"
#include "dist_calculator.h"
#undef assert
#include "assert.h"

using std::vector;

bool SymmetricChecker::check(const ProcessState& state, size_t symmetric)
{
    for(size_t i = 0; i < state.numVertecies; ++i) {
        vertecies_[i] = (symmetric ^ state.vertecies[i]);
    }
    std::sort(vertecies_, vertecies_ + state.numVertecies);
    return !std::lexicographical_compare(vertecies_, vertecies_ + state.numVertecies,
            state.vertecies, state.vertecies + state.numVertecies);
}

bool FinalSymmetricChecker::check(const ProcessState& state)
{
    assert(state.numVertecies > 0, "state.numVertecies > 0");
    if (state.vertecies[0] != 0) {
        return false;
    }
    for(size_t v = 1; v < state.numVertecies; ++v) {
        if (!helperChecker_.check(state, state.vertecies[v])) {
            incrementFalseNumber();
            return false;
        }
    }
    return true;
}

bool OnlineSymmetricChecker::check(const ProcessState& state)
{
    assert(state.numVertecies > 0, "state.numVertecies > 0");
    if (state.vertecies[0] != 0) {
        return false;
    }
    size_t lastv = state.vertecies[state.numVertecies - 1];
    if (!helperChecker_.check(state, lastv)) {
        incrementFalseNumber();
        return false;
    }
    return true;
}

bool CoordNChecker::check(const size_t* const a, size_t k)
{
    if (k == 1) {
        size_t v = a[0];
        return (v & (v + 1)) == 0;
    }

    size_t* ctmp = tmp[k];
    for(size_t i = 1; i < k; ++i) {
        ctmp[i - 1] = (a[0] | a[i]);
    }
    if (!check(ctmp, k - 1)) {
        return false;
    }
    bool modified = false;
    for(size_t i = 1; i < k; ++i) {
        size_t nvalue = (a[0] & a[i]);
        if (ctmp[i - 1] != nvalue) {
            ctmp[i - 1] = nvalue;
            modified = true;
        }
    }
    if (modified) {
        return check(ctmp, k - 1);
    } else {
        return true;
    }
}

OnlineSymmetricCoordChecker::OnlineSymmetricCoordChecker()
    :checker_(new CoordNChecker())
{
}

bool OnlineSymmetricCoordChecker::check(const ProcessState& state)
{
    size_t lastv = state.vertecies[state.numVertecies - 1];
    if (state.numVertecies > 1) {
        //Check that new vertex has not less number of bits.
        size_t preLastv = state.vertecies[state.numVertecies - 2];
        if (distanceCalculator(0, lastv) < distanceCalculator(0, preLastv)) {
            incrementFalseNumber();
            return false;
        }
        if (state.numVertecies <= MAX_PROCESSED) {
            if (!checker_->check(&state.vertecies[1],
                                  state.numVertecies - 1)) {
                incrementFalseNumber();
                return false;
            }
        }
    }
    return true;
}

bool FinalDimensionChecker::check(const ProcessState& state)
{
    size_t ors = 0;
    for(size_t i = 0; i < state.numVertecies; ++i) {
        ors |= state.vertecies[i];
    }
    if (ors + 1 != SIZE_VMSK) {
        incrementFalseNumber();
        return false;
    }
    return true;
}

bool OnlineDimensionChecker::check(const ProcessState& state)
{
    if (state.numVerteciesWithLargestBit > 0)
    {
        return true;
    } else {
        incrementFalseNumber();
        return false;
    }
}

bool FinalBiparateChecker::check(const ProcessState& state)
{
    if (!biparate(state.subGraph))
    {
        return true;
    } else {
        incrementFalseNumber();
        return false;
    }
}

bool FinalNaiveColoringChecker::check(const ProcessState& state)
{
    if (naiveColoring(state.subGraph) > n + 1)
    {
        return true;
    } else {
        incrementFalseNumber();
        return false;
    }
}

bool FinalCorrectColoringChecker::check(const ProcessState& state)
{
    if (!correctColoring(state.subGraph))
    {
        return true;
    } else {
        incrementFalseNumber();
        return false;
    }
}

bool OnlineMaxDegreeChecker::check(const ProcessState& state)
{
    bool res = state.potentialDegree.degreeSet.maxValue() > maxDegree_;
    if (!res) {
        incrementFalseNumber();
    }
    return res;
}

bool OnlineColoringChecker::check(const ProcessState& state)
{
    bool res = state.colorInfo.maxColor.maxValue() > maxColor_;
    if (!res) {
/*        size_t mc = 0;
        for(size_t v = 0; v < state.newGraph->numVertecies(); ++v) {
            if (state.getted[v] == 0) {
                continue;
            }
            mc = std::max(mc, state.colorInfo.color[v]);
            const vector<size_t>& inc = state.newGraph->incendents(v);
            for(size_t j = 0; j < inc.size(); ++j) {
                size_t u = inc[j];
                if (state.getted[u] == 0) {
                    continue;
                }
                assert((state.colorInfo.color[u] != state.colorInfo.color[v]));
            }
        }
        assert(mc <= maxColor_);*/
        incrementFalseNumber();
    }
    return res;
}
